home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / ISSUE02 / TPACK / TPACK.ZIP / OKCORE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-06-01  |  13.6 KB  |  409 lines

  1. {------------------------------------------------------------------------------}
  2. {UNREGISTERED VERSION (6/1/95) PLEASE REDISTRIBUTE IN tPACK.ZIP!
  3.  This revision does not contain everything, nor are the exciting
  4.  DataSetReporter and ExtendedMenu[Item] components included.
  5.  Use SWREG#5906 to receive these, icons and a help file for $130.
  6.  You must register when using this code in a business application!
  7.  You'll receive a license to use this code in up to 50 copies of
  8.  any app you write. In turn you will get responsive e-mail
  9.  tech support and enhancements till I run out of registrations
  10.  or suggestions. Meanwhile.. enjoy the code. Bye! I'll make more.
  11.  {(C)'1995 Michael/Ax-Systems, 71560,1754@Compuserve.com}
  12. {------------------------------------------------------------------------------}
  13.  
  14. unit OkCore; {Home of TOk, the OK Component.}
  15.  
  16. {base components to start a process and signal/negotiate go/stop.}
  17.  
  18. {Sounds simple, but boy, this was my first component and kept me scratching my head
  19. for a long time. YOU need this functionality now and here it is. Figure it out.
  20. Pardon the disjointed comments, I renamed and cut some esoteric 'logic-lego' pieces.}
  21.  
  22. interface
  23.  
  24. uses
  25.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  26.   Forms, Dialogs, StdCtrls
  27. , Retry
  28. , PasUtils
  29. , UserInfo;
  30.  
  31. type
  32.  
  33. {------------------------------------------------------------------------------}
  34. {TOk defines the essential stopability that other components rely on.
  35. It requests permission to change states and performs tries on on/off
  36. it also can disable 'other' windows when running to make is seem modal. <explore this.useful}
  37.  
  38.   TOk = class;
  39.  
  40.   TOkState = (stsActive,stsCritical,stsReady,stsCanceled,stsDisabled);  {must improve!}
  41.  
  42.   TOkAware = class(TDialogShell)
  43.   private
  44.     fEnabled:        Boolean;  {allow changes only if enabled}
  45.     fActive:         Boolean;   {read only, true until done}
  46.     fProcessMessages: Boolean;
  47.   protected
  48.     procedure SetActive(Flag:Boolean);  virtual;
  49.     function GetActive:Boolean;
  50.   public
  51.     constructor Create(AOwner:TComponent); override;
  52.     procedure Execute; override;
  53.   published
  54.     property  Active: Boolean   read GetActive   write SetActive;
  55.     property  Enabled: Boolean  read fEnabled  write fEnabled default true;
  56.     property  ProcessMessages: Boolean read fProcessMessages write fProcessMessages default true;
  57.   end;
  58.  
  59. {------------------------------------------------------------------------------}
  60.  
  61.   EOkAlreadyActive = class(Exception);
  62.   EOkDoAlreadyActive = class(EOkAlreadyActive);
  63.  
  64. {------------------------------------------------------------------------------}
  65.  
  66.   TOkOnOkStart  = procedure(Sender: TOk;Var CanStart:Boolean) of object;
  67.   TOkOnOkStop   = procedure(Sender: TOk;Var CanStop:Boolean) of object;
  68.   TOkOnOkChange = procedure(Sender: TOk;NewState:TOkState;Var CanChange:Boolean) of object;
  69.  
  70.   TOk = class(TOkAware)
  71.     {TOk remains completely invisible but let you hookup begin/end procs that
  72.     make it simple for you to hook up changes to captions or do whatever
  73.     you need to keep the user happy while running your Ok action. To use,
  74.     set Active:=True when beginning your loop, then check 'Active' or 'Stop'
  75.     while looping to Process Messages and exit properly. Your Cancel button can
  76.     signal a normal or cancel outcome by setting Active:=False or Canceled:=True.
  77.     Deactivating in either ways can be denied by the OnOkStop procedure.}
  78.  
  79.     {simple, right?
  80.      you could call this component from a button like this:
  81.       Ok1.Active:=not Ok1.Active;
  82.       if Ok1.Active then
  83.         Button1.Caption:='Running'
  84.       else
  85.         Button1.Caption:='Stopped';
  86.     }
  87.   private
  88.     { Private declarations }
  89.     fCritical:       Boolean; {disable OkBox button, on hold}
  90.     fCanceled:       Boolean; {Ok canceled on last try}
  91.     fFrozen:         Boolean;   {other forms disabled while true}
  92.     fFreeze:         Boolean;   {disable other forms while true}
  93.     fOnOkStart:      TOkOnOkStart;{OnOkStart proc to ok-ok. eg. oks ative=true}
  94.     fOnOkChange:     TOkOnOkChange;{ok-ok. eg. oks ative=true}
  95.     fOnOkStop:       TOkOnOkStop;  {ok-ok. eg. oks ative=true}
  96.   protected
  97.     { Protected declarations }
  98.     procedure   SetActive(Flag:Boolean);             override;
  99.     procedure   SetEnabled(Flag:Boolean);            virtual;
  100.     procedure   SetStop(Flag:Boolean);               virtual;
  101.     procedure   SetCritical(Flag:Boolean);           virtual;
  102.     procedure   SetCanceled(Flag:Boolean);           virtual;
  103.     procedure   SetState(State:TOkState);            virtual;
  104.     procedure   SetFrozen(Flag:Boolean;ButNot:HWND); virtual;
  105.     function    GetStop:Boolean;
  106.     function    GetState:TOkState;
  107.     function    GetStringState:String;
  108.     procedure   DoOkStart(Var CanStart:Boolean);                     virtual;
  109.     procedure   DoOkChange(NewState:TOkState;Var CanChange:Boolean); virtual;
  110.     procedure   DoOkStop(Var CanStop:Boolean);                       virtual;
  111.     function    FreezeFormHandle:HWND;               virtual;
  112.   public
  113.     { Public declarations }
  114.     constructor Create(AOwner:TComponent);           override;
  115.     procedure   Run(Sender:TObject;Var Success: Boolean); virtual;
  116.     procedure   OkOn;                                virtual;
  117.     procedure   OkOff;                               virtual;
  118.     procedure   Reset;                               virtual;
  119.     function    BenchmarkLoopsPerSecond:LongInt;
  120.     function    StringState(State:TOkState):String;
  121.   published
  122.     property Enabled: Boolean            read fEnabled  write SetEnabled default true;
  123. {    property Active: Boolean             read fActive   write SetActive;}
  124.     {note if you disable, only enabled and state will change. you can not
  125.     disable the control in a critical section.}
  126.     property Ok: Boolean                 read fActive   write SetActive; {ALIAS}
  127.     property Stop: Boolean               read GetStop   write SetStop default true;
  128.     property Critical: Boolean           read fCritical write SetCritical;
  129.     property Canceled: Boolean           read fCanceled write SetCanceled;
  130.     property State: TOkState             read GetState  write SetState default stsReady;
  131.     property StateString: String         read GetStringState;
  132.     property FreezeForms: Boolean        read fFreeze   write fFreeze;
  133.     property OnOkStart: TOkOnOkStart     read fOnOkStart write fOnOkStart;
  134.     property OnOkChange: TOkOnOkChange   read fOnOkChange write fOnOkChange;
  135.     property OnOkStop: TOkOnOkStop       read fOnOkStop write fOnOkStop;
  136.   end;
  137.  
  138.  
  139. implementation
  140.  
  141. {------------------------------------------------------------------------------}
  142.  
  143. constructor TOkAware.Create(AOwner:TComponent);
  144. begin
  145.   inherited create(AOwner);
  146.   fEnabled:=true;
  147.   fProcessMessages:=true;
  148. end;
  149.  
  150. procedure TOkAware.SetActive(Flag:Boolean);
  151. begin
  152.   if fActive<>Flag then
  153.     fActive:=Flag;
  154. end;
  155.  
  156. function TOkAware.GetActive:Boolean;
  157. begin
  158.   if fProcessMessages then
  159.     Application.ProcessMessages;
  160.   Result:=fActive;
  161. end;
  162.  
  163. procedure TOkAware.Execute;
  164. begin
  165.   Active:=True;
  166. end;
  167.  
  168. {------------------------------------------------------------------------------}
  169. {Let's begin.. here goes the 'root' component, e.g.  the Ok capability.}
  170.  
  171. constructor TOk.Create(AOwner:TComponent);
  172. begin
  173.   inherited create(AOwner);
  174.   fEnabled:=True;
  175. end;
  176.  
  177. procedure TOk.Reset;
  178. {Unconditially resets the component and puts it in ready mode. use at own risk.
  179. {this methd allows you to stop a OkTry regardless of the callback method's
  180. opinion. we simply take it out, shut off and put it back. it never knows.}
  181. var
  182.   e:TOkOnOkStop;
  183. begin
  184.   e:=fOnOkStop;
  185.   fOnOkStop:=nil;
  186.   State:=stsReady;
  187.   {note: this is the only time we actually resort to changing the component's
  188.   state. usually we just manipulate the flags directly but here we want to take
  189.   advantage of the override logic in SetState.}
  190.   {you might think we should make the status canceled if we shut down a loop.
  191.   that wouldn't be right either because we really 'excepted' out of the OkTry.}
  192.   fOnOkStop:=e;
  193. end;
  194.  
  195. procedure TOk.Run(Sender:TObject;Var Success: Boolean);
  196. begin
  197.   SetActive(True);
  198.   SetActive(False);
  199. end;
  200.  
  201. procedure TOk.OkOn;
  202. begin
  203.   Active:=True;
  204. end;
  205.  
  206. procedure TOk.OkOff;
  207. begin
  208.   Active:=False;
  209. end;
  210.  
  211. function TOk.BenchmarkLoopsPersecond:Longint;
  212. begin
  213.   result:=-1;
  214.   {instantiate timer w/proc to signal end (could use another ok)
  215.   then count how often we can turn ok on/off inside that time.}
  216. end;
  217.  
  218. procedure TOk.SetEnabled(Flag:Boolean);
  219. begin
  220.   if Flag<>fEnabled then begin
  221.     if (not Flag) and fActive and fCritical then {can not stop in a critical section!}
  222.       Exit;
  223.     if fActive and (Flag=false) then
  224.       Active:=False; {turn off. OnOkStop may deny.}
  225.    {implement okchange!}
  226.     fEnabled:=fActive or Flag;
  227.     end;
  228. end;
  229.  
  230. procedure TOk.SetCanceled(Flag:Boolean);
  231. begin
  232.   if fEnabled and Flag<>fCanceled then begin
  233.     if flag then       {do not activate when resetting flag}
  234.       SetStop(Flag);
  235.     if Flag<>fCanceled then begin
  236.       DoOkChange(stsCanceled,Flag);
  237.       fCanceled:=Flag;
  238.       end;
  239.     end;
  240. end;
  241.  
  242. procedure TOk.SetStop(Flag:Boolean);
  243. begin
  244.   Active:=not Flag;
  245. end;
  246.  
  247. function TOk.GetStop:Boolean;
  248. begin
  249.   Result:=not Active;
  250. end;
  251.  
  252. procedure TOk.SetActive(Flag:Boolean);
  253. var
  254.   Close: Boolean;
  255. begin
  256.   if fEnabled and Flag<>fActive then begin
  257.     if Flag then begin
  258.       if fActive then
  259.         raise EOkAlreadyActive.Create('TOk: Already Active');
  260.       fCanceled:=False;
  261.       DoOkChange(stsActive,Flag);
  262.       if flag then
  263.         DoOkStart(Flag);
  264.       fActive:=false;
  265.       if not flag then
  266.         exit;
  267.       end
  268.     else begin
  269.       if fActive and fCritical then {can not stop in a critical section!}
  270.         Exit;
  271.       Close:= true;
  272.       DoOkChange(stsReady,close);
  273.       if Close then
  274.         DoOkStop(close);
  275.       fActive:=true;
  276.       if not Close then
  277.         exit;
  278.       end;
  279.     if flag<>fActive then begin
  280.       fActive:=Flag;
  281.       SetFrozen(fActive and fFreeze,FreezeFormHandle);
  282.       end;
  283.     end;
  284. end;
  285.  
  286. procedure TOk.SetCritical(Flag:Boolean);
  287. {OkTry can not be stopped when in a critical section}
  288. {it can start in 'critical' mode where it can not be stopped-
  289. however the component can not be enabled without resetting critical to neutral,
  290. note that 'enabling' is not 'activating'. you can go from ready mode to critical,
  291. just going from disabled to critical is not possible. makes sense?}
  292. begin
  293.   if fEnabled and Flag<>fCritical then
  294.     fCritical:={fActive and} Flag;
  295. end;
  296.  
  297. procedure TOk.SetState(State:TOkState);
  298. {by setting the state, you get a shortcut way to change the properties
  299. you want to change. REMEMBER!: CRITICAL=TRUE forces the box to stay on,
  300. ENABLE=FALSE forces it to stay off. no matter how often you try, these
  301. properties will block you from changing others. In critical sections the
  302. OnOkStop procedure is never called.}
  303. begin
  304.   case State of
  305.     stsActive:   if fCritical and fActive then
  306.                    Critical:= False {transit back from critical to active}
  307.                  else
  308.                    Active:=   True;
  309.     stsCritical: if fActive then
  310.                    Critical:= True;
  311.     stsReady:    begin
  312.                  if fEnabled=false then
  313.                    fEnabled:=True;
  314.                  if fCritical then
  315.                    fCritical:=False;
  316.                  Canceled:=False;
  317.                  end;
  318.     stsCanceled: Canceled:= True;
  319.     stsDisabled: Enabled:=  False;
  320.     end;
  321. end;
  322.  
  323. function TOk.GetState:TOkState;
  324. {you definitely must play with this component in the object inspector before
  325. using it. the CRITICAL/ENABLED flags must be understood to be useful. the 'State'
  326. property should make the logic clearer.}
  327. begin
  328.   if not fEnabled then
  329.     Result:=stsDisabled
  330.   else
  331.     if fCanceled then
  332.       Result:=stsCanceled
  333.     else
  334.       if not fActive then
  335.         Result:=stsReady
  336.       else
  337.         if fCritical then
  338.           Result:=stsCritical
  339.         else
  340.           Result:=stsActive;
  341.   if fProcessMessages then
  342.     Application.ProcessMessages;
  343. end;
  344.  
  345. function TOk.GetStringState:String;
  346. begin
  347.   result:=StringState(State);
  348. end;
  349.  
  350. function TOk.StringState(State:TOkState):String;
  351. begin
  352.   case State of
  353.   stsActive:      Result:='Active';
  354.   stsCritical:    Result:='Critical';
  355.   stsReady:       Result:='Ready';
  356.   stsCanceled:    Result:='Canceled';
  357.   stsDisabled:    Result:='Disabled';
  358.   end;
  359. end;
  360.  
  361. procedure TOk.SetFrozen(Flag:Boolean;ButNot:HWND);
  362. var
  363.   i:longint;
  364. begin
  365.   if Flag<>fFrozen then begin
  366.     fFrozen:=Flag;
  367.     for i:=0 to Screen.FormCount-1 do
  368.       if ButNot <> Screen.Forms[i].Handle then
  369.         with Screen.Forms[i] do
  370.           Enabled := not Enabled;
  371.     end;
  372. end;
  373.  
  374. function TOk.FreezeFormHandle:HWND;
  375. {the purpose of this function is to be replaced by a descendant in case the
  376. usual choice of forms to be unfrozen is not right, and frankly, to allow us
  377. to focus either on the derived OkBox or on the currently active form}
  378. begin
  379.   result:=Screen.ActiveForm.Handle;
  380. end;
  381.  
  382. {}
  383.  
  384. procedure TOk.DoOkStart(Var CanStart:Boolean);
  385. begin
  386.   if assigned(fOnOkStart) then
  387.     fOnOkStart(Self,CanStart);
  388.   if CanStart then begin
  389.     fActive:=CanStart;
  390.     fActive:=CanStart;
  391.     end;
  392. end;
  393.  
  394. procedure TOk.DoOkChange(NewState:TOkState;Var CanChange:Boolean);
  395. begin
  396.   if assigned(fOnOkChange) then fOnOkChange(Self,NewState,CanChange);
  397. end;
  398.  
  399. procedure TOk.DoOkStop(Var CanStop:Boolean);
  400. begin
  401.   if assigned(fOnOkStop) then
  402.     fOnOkStop(Self,CanStop);
  403. end;
  404.  
  405. {------------------------------------------------------------------------------}
  406.  
  407. end.
  408.  
  409.